/*******************************************************************************
 *                           TacticaHimura.java                                *
 *                           Cesar Himura Elric                                *
 *                              JavaCup 2009                                   *
 *******************************************************************************/

package org.javahispano.javacup.tacticas_aceptadas.Himura;

import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.Tactica;
import org.javahispano.javacup.modelo.SituacionPartido;
import org.javahispano.javacup.modelo.TacticaDetalle;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.JugadorDetalle;

import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;

public class TacticaHimura implements Tactica
{
    private SituacionPartido sp = null;

    private TacticaHimuraDetalle detalle = new TacticaHimuraDetalle();

    private LinkedList<Comando> comandos = new LinkedList<Comando>();

    private final int X_EQUESTRIS = 0;
    private final int RIVALES = 1;

    private double ang_trayectoria = 0;
    private double ang_trayectoria_ant = 0;
    private double DISTANCIA_FUERA = 32d;
    
    private int[] jcp = new int[2];

    private int utb = -1;
    private int utb_ant = -1;
    private int pB = 0;

    private Balon balonAnt = null;
    private Balon balon = null;

    private Cerebro c = new Cerebro();

      Posicion alineacion1[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-6.895104895104895,-30.16968325791855),
        new Posicion(5.706293706293707,-30.16968325791855),
        new Posicion(16.88111888111888,-29.457013574660635),
        new Posicion(-18.307692307692307,-29.694570135746606),
        new Posicion(24.013986013986013,-0.7126696832579186),
        new Posicion(-24.65648854961832,-2.3507462686567164),
        new Posicion(-0.23776223776223776,-11.165158371040723),
        new Posicion(-9.272727272727272,33.49547511312217),
        new Posicion(0.0,9.502262443438914),
        new Posicion(9.986013986013985,33.73303167420815)
    };

    Posicion alineacion2[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-11.16030534351145,-31.082089552238806),
        new Posicion(11.16030534351145,-31.6044776119403),
        new Posicion(27.251908396946565,-27.94776119402985),
        new Posicion(-29.84732824427481,-26.902985074626866),
        new Posicion(8.564885496183205,-7.574626865671642),
        new Posicion(-10.641221374045802,-7.052238805970149),
        new Posicion(27.251908396946565,4.440298507462686),
        new Posicion(-29.32824427480916,3.3955223880597014),
        new Posicion(-0.2595419847328244,19.067164179104477),
        new Posicion(-0.2595419847328244,35.78358208955224)
    };

    Posicion alineacion3[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-11.16030534351145,-31.082089552238806),
        new Posicion(11.16030534351145,-31.6044776119403),
        new Posicion(26.732824427480914,-20.111940298507463),
        new Posicion(-29.32824427480916,-21.67910447761194),
        new Posicion(0.2595419847328244,-0.26119402985074625),
        new Posicion(-18.946564885496183,-0.26119402985074625),
        new Posicion(18.946564885496183,-0.26119402985074625),
        new Posicion(-19.46564885496183,35.78358208955224),
        new Posicion(-0.2595419847328244,19.067164179104477),
        new Posicion(18.946564885496183,35.26119402985075)
    };

    Posicion alineacion4[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-11.16030534351145,-31.082089552238806),
        new Posicion(11.16030534351145,-31.6044776119403),
        new Posicion(28.290076335877863,-28.470149253731343),
        new Posicion(-28.290076335877863,-28.470149253731343),
        new Posicion(11.16030534351145,-1.3059701492537314),
        new Posicion(-10.641221374045802,-0.7835820895522387),
        new Posicion(-27.251908396946565,31.6044776119403),
        new Posicion(-10.641221374045802,30.559701492537314),
        new Posicion(9.603053435114505,28.992537313432837),
        new Posicion(25.69465648854962,28.992537313432837)
    };

    Posicion alineacion5[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-11.16030534351145,-35.78358208955224),
        new Posicion(12.717557251908397,-35.26119402985075),
        new Posicion(28.290076335877863,-28.470149253731343),
        new Posicion(-28.290076335877863,-28.470149253731343),
        new Posicion(14.793893129770993,-18.544776119402986),
        new Posicion(-17.389312977099234,-19.58955223880597),
        new Posicion(-23.618320610687025,-0.7835820895522387),
        new Posicion(5.969465648854961,-5.485074626865671),
        new Posicion(0.2595419847328244,-0.26119402985074625),
        new Posicion(22.580152671755727,-1.3059701492537314)
    };

    Posicion alineacion6[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-11.16030534351145,-35.78358208955224),
        new Posicion(12.717557251908397,-35.26119402985075),
        new Posicion(28.290076335877863,-28.470149253731343),
        new Posicion(-28.290076335877863,-28.470149253731343),
        new Posicion(14.793893129770993,-18.544776119402986),
        new Posicion(-17.389312977099234,-19.58955223880597),
        new Posicion(-23.618320610687025,-0.7835820895522387),
        new Posicion(6.4885496183206115,-6.529850746268657),
        new Posicion(-6.4885496183206115,-6.529850746268657),
        new Posicion(22.580152671755727,-1.3059701492537314)
    };

    public Posicion[] getPosicionSaca(SituacionPartido sp) {
        return alineacion5;
    }

    public Posicion[] getPosicionRecive(SituacionPartido sp) {
        return alineacion6;
    }

    public TacticaDetalle getDetalle() {
        return detalle;
    }

    public List<Comando> ejecutar(SituacionPartido sp)
    {
        comandos.clear();

        this.sp = sp;

        for (int i = 0; i < 11; i++) {
            if(i != jcp[0] && i != jcp[1])
                comandos.add(new ComandoIrA(i, alineacion1[i]));
        }

        int indMasCercano = sp.balon().indiceMasCercano(sp.misJugadores());
        int sDefensor = getSegundoDefensor();

        if(jcp[0] != 6 && jcp[1] != 6 && indMasCercano != 6)
            mueveMedioIzquierdo();
        if(jcp[0] != 5 && jcp[1] != 5 && indMasCercano != 5)
            mueveMedioDerecho();
        if(jcp[0] != 8 && jcp[1] != 8 && indMasCercano != 8)
            mueveDelanteroIzquierdo();
        if(jcp[0] != 10 && jcp[1] != 10 && indMasCercano != 10)
            mueveDelanteroDerecho();
        if(jcp[0] != 9 && jcp[1] != 9 && indMasCercano != 9)
            mueveMedioOfensivo();

        mueveDefensas();

        if(sp.misJugadores()[indMasCercano].distancia(sp.balon()) < sp.rivales()[sp.balon().indiceMasCercano(sp.rivales())].distancia(sp.balon()))
            utb = X_EQUESTRIS;
        else
            utb = RIVALES;

        balon = new Balon(sp.balon().getX(), sp.balon().getY());
        balon.setAltura(sp.alturaBalon());

        double dR = balon.distancia(sp.rivales()[sp.balon().indiceMasCercano(sp.rivales())]);
        double dX = balon.distancia(sp.misJugadores()[indMasCercano]);

        ganaPosicion();

        if(sp.saco())
        {
            for(int index = 0; index < 11; index++)
            {
                if(sp.rivales()[index].distancia(sp.balon()) >= Constantes.DISTANCIA_SAQUE)// * 1.5)
                {
                    if(indMasCercano == 0 || balon.getY() == -47)
                        comandos.add(new ComandoGolpearBalon(indMasCercano, Constantes.centroArcoSup, 1, true));
                    else
                        paseX(index);
                }
            }
        }//if saco
        else
        {
            switch(indMasCercano)
            {
                case 0: if(puedeRematar(indMasCercano))
                            comandos.add(new ComandoGolpearBalon(0, Constantes.centroArcoSup, 1, true));
                        
                default: if(puedeRematar(indMasCercano))
                            tomaDecision(indMasCercano);
            }//switch

            Posicion[] X = sp.misJugadores();
            
            List jrm = new ArrayList();
            for(int nx = 1; nx < X.length; nx++)
            {
                int nr = X[nx].indiceMasCercano(sp.rivales());

                boolean nrm = false;

                for(int k = 0; k < jrm.size(); k++)
                {
                    if(nr == Integer.parseInt(jrm.get(k).toString()))
                    {
                        nrm = true;
                        break;
                    }
                }

                if(pB == X_EQUESTRIS)
                {
                    if(nr > -1)
                        if(sp.rivales()[nr].getY() <= 0.00 && !nrm)
                        {
                            jrm.add(nr);

                            if(nx > 0 && nx != indMasCercano && (nx != sDefensor && dR > dX) && nx != jcp[0] && nx != jcp[1])
                                    setMarcaje(nx, nr);
                        }
                }
                else
                {
                    if(nr > -1)
                    {
                        if(!nrm && nr != getPorteroRival(sp.detalleJugadoresRivales()))
                        {
                            jrm.add(nr);

                            if(nx > 0 && nx != indMasCercano && nx != sDefensor && nx != jcp[0] && nx != jcp[1])
                            {
                                if((nx == 8 || nx == 9 || nx == 10) && sp.rivales()[nr].getY() > 0)
                                    setMarcaje(nx, nr);
                                if(nx < 8)
                                    setMarcaje(nx, nr);
                            }
                        }
                    }//nr > -1
                }
            }

            double xPortero = X[0].getX();
            double yPortero = X[0].getY();

            if(balon.getY() >= 0)
            {
                xPortero = Constantes.centroCampoJuego.getX();
                yPortero = (Constantes.ANCHO_AREA_GRANDE + 1.0) - (Constantes.LARGO_CAMPO_JUEGO / 2);
            }
            else
            {
                Posicion p = lanzaPortero();

                xPortero = p.getX();
                yPortero = p.getY();
            }

            comandos.add(new ComandoIrA(0, new Posicion(xPortero, yPortero)));
        }

        comandos.add(new ComandoIrA(indMasCercano, sp.balon()));

        if(sDefensor > 0 && dR < dX)
            comandos.add(new ComandoIrA(sDefensor, sp.balon()));
        
        balonAnt = balon;

        utb_ant = utb;

        return comandos;
    }

    private void tomaDecision(int nX)
    {
        double dist = sp.balon().distancia(Constantes.centroArcoSup);

        if(dist <= DISTANCIA_FUERA)
        {
            disparoAlArco(nX, dist);
        }
        else
        {
            double r = 7d;

            int nr = sp.balon().indiceMasCercano(sp.rivales());
            int nr2 = -1;

            if(sp.misJugadores()[nX].getY() - 0.5 > sp.rivales()[nr].getY())
            {
                nr = getSegundoMasCercano(sp.misJugadores()[nX], RIVALES);
            }

            if(nr2 > -1)
            {
                if(sp.balon().distancia(sp.rivales()[nr]) <= 0.5 || sp.balon().distancia(sp.rivales()[nr2]) <= r)
                {
                    paseX(nX);
                    return;
                }
            }

            if(sp.balon().distancia(sp.rivales()[nr]) <= r)// && sp.misJugadores()[nX].getY()+1.5 < sp.rivales()[nr].getY())
            {
                paseX(nX);
            }
            else
            {
                if(nX > 0)
                {
                    if(nX < 5 && -Constantes.LARGO_CAMPO_JUEGO/2/4 < balon.getY())
                    {
                        paseX(nX);
                        comandos.add(new ComandoIrA(nX, alineacion1[nX]));
                    }
                    else
                    {
                        regatea(nX);
                    }
                }
            }
        }
    }//tomaDecision

    private void ganaPosicion()
    {
        double x;
        double y;
        double z;
        double dx;
        double dy;
        //double dr;
        double dz;

        int jxs = 0;

        boolean suelo = false;

        List<double[]> list = new ArrayList<double[]>();

        if(balonAnt != null && balon != null)
        {
            x = balon.getX();
            y = balon.getY();
            z = balon.getAltura();

            ang_trayectoria = balon.angulo(balonAnt);
            
            if(ang_trayectoria != ang_trayectoria_ant)
            {
                ang_trayectoria_ant = ang_trayectoria;

                pB = utb_ant;

                dx = balon.getX() - balonAnt.getX();
                dy = balon.getY() - balonAnt.getY();
                dz = balon.getAltura() - balonAnt.getAltura();
                
                for(int it = 1; it <= 30; it++)
                {
                    if (!suelo && z == 0 && dz >= 0 && dz < Constantes.G * 3) {//condicion para que se arrastre
                        suelo = true;
                    }
                    if (suelo) {
                        //balon = balon.moverPosicion(balonDx, balonDy);
                        dx = dx * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                        dy = dy * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                    } else {
                        //z = round(z + dz, Constantes.G);
                        //balon = balon.moverPosicion(balonDx, balonDy);
                        dz = c.round(dz - Constantes.G, Constantes.G);
                        dx = dx * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                        dy = dy * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                        if (z <= 0) {
                            dz = (-dz - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                            dz = c.round(dz, Constantes.G);
                        }
                    }

                    x = x + dx;
                    y = y + dy;
                    z = z + dz;
                    
                    if(z <= Constantes.ALTURA_CONTROL_BALON)
                    {
                        Posicion p = new Posicion(x, y);
                        int jx = p.indiceMasCercano(sp.misJugadores());
                        double d = p.distancia(sp.misJugadores()[jx]);

                        if(detalle.getJugadores()[jx].getVelocidad() * it >= d)
                        {
                            comandos.add(new ComandoIrA(jx, p));
                            jcp[jxs] = jx;
                            jxs++;

                            if(jxs == 2)
                                break;
                        }
                        else
                        {
                            double[] datos = {jx, x, y, p.distancia(sp.misJugadores()[jx])};
                            list.add(datos);
                        }
                    }
                }//for

                if(list.size() > 0 && jxs < 2)
                {
                    double[][] pos = c.ordenaArrayDistancias(c.toArray(list), list.get(0).length);

                    if(jxs == 1 && pos.length >= 1)
                    {
                        jcp[1] = (int)pos[0][0];
                        comandos.add(new ComandoIrA((int)pos[0][0], new Posicion(pos[0][1],pos[0][2])));
                    }
                    else
                    {
                        if(pos.length >= 2)
                        {
                            jcp[0] = (int)pos[0][0];
                            jcp[1] = (int)pos[1][0];
                            comandos.add(new ComandoIrA((int)pos[0][0], new Posicion(pos[0][1],pos[0][2])));
                            comandos.add(new ComandoIrA((int)pos[1][0], new Posicion(pos[1][1],pos[1][2])));
                        }
                    }
                }//if list
            }//if ang_trayectoria != ang_trayectoria_ant
        }
    }

    private Posicion lanzaPortero()
    {
        double[] recta = null;
        double x = 0;
        double y = Constantes.posteIzqArcoInf.getY() + 0.5;

        if(balonAnt != null && balon != null)
        {
            if(balon.getY() < -Constantes.LARGO_CAMPO_JUEGO/2 + 15 && Constantes.ANCHO_AREA_GRANDE/2 + 5 > balon.getX()
               && balon.getX() > -Constantes.ANCHO_AREA_GRANDE/2 - 5)
            {
                double dx = balon.getX()-balonAnt.getX();
                double dy = balon.getY()-balonAnt.getY();

                if(dx < 0.09 && dy < 0.09)
                    return sp.balon();
            }

            recta = c.getRecta(balonAnt.getX(), balonAnt.getY(), balon.getX(), balon.getY());

            x = (y - recta[2]) / recta[1];

            x = (Double.isNaN(x)) ? 0 : x;

            if(x <= Constantes.posteIzqArcoInf.getX())
                x = Constantes.posteIzqArcoInf.getX() + Constantes.DISTANCIA_CONTROL_BALON_PORTERO - 0.2;

            if(x >= Constantes.posteDerArcoInf.getX())
                x = Constantes.posteDerArcoInf.getX() - Constantes.DISTANCIA_CONTROL_BALON_PORTERO - 0.2;
        }

        return new Posicion(x, y);
    }

    private void setMarcaje(int nJ, int nJC)
    {
        Posicion[] equipo = sp.misJugadores();
        Posicion[] rivales = sp.rivales();

        Posicion posicion = null;

        if(nJ > 0 && nJC > -1)
            if(c.getDistancia(equipo[nJ].getX(), equipo[nJ].getY(),rivales[nJC].getX(),rivales[nJC].getY()) < 200d)
            {
                posicion = getCoordenadasMarcaje(rivales[nJC], sp.balon());

                comandos.add(new ComandoIrA(nJ, posicion));
            }
    }

    private Posicion getCoordenadasMarcaje(Posicion nJC, Posicion balon)
    {
        double x = nJC.getX() + (1d * (balon.getX() - nJC.getX()) / nJC.distancia(balon));
        double y = nJC.getY() + (1d * (balon.getY() - nJC.getY()) / nJC.distancia(balon));

        return new Posicion(x, y);
    }

    private void regatea(int nX)
    {
        double r = 4.99999; //radio de accion
        double xRegate = sp.balon().getX();
        double yRegate = sp.balon().getY();
        final double dxRegate = 0.9;

        boolean hayRival = false;

        int nC = sp.misJugadores()[nX].indiceMasCercano(sp.rivales());

        if(sp.misJugadores()[nX].getY() > sp.rivales()[nC].getY())
            nC = getSegundoMasCercano(sp.misJugadores()[nX], RIVALES);

        if(sp.balon().distancia(sp.rivales()[nC]) <= r && sp.misJugadores()[nX].getY()+1.5 < sp.rivales()[nC].getY())
        {
            hayRival = true;
            if(sp.rivales()[nC].getX() < sp.misJugadores()[nX].getX())//el rival esta a la izquierda
            {
                xRegate += dxRegate;
            }
            else
            {
                if(sp.rivales()[nC].getX() > sp.misJugadores()[nX].getX())//el rival esta a la derecha
                {
                    xRegate -= dxRegate;
                }
                else//el rival esta de frente
                {
                    comandos.add(new ComandoGolpearBalon(nX, Constantes.centroArcoSup, 1, true));
                }
            }
        }//if distancia

        if(sp.balon().getY() > 25)
            if(!hayRival)
                comandos.add(new ComandoGolpearBalon(nX, Constantes.centroArcoSup, 0.4, false));
            else
                comandos.add(new ComandoGolpearBalon(nX, new Posicion(xRegate, yRegate + 0.8), 0.4, false));
        else
            comandos.add(new ComandoGolpearBalon(nX, new Posicion(xRegate, yRegate + 0.8), 0.4, false));
    }

    private int getSegundoDefensor()
    {
        int[] X = getMisJugadoresMasCercanos(sp.balon());

        int mCB = sp.balon().indiceMasCercano(sp.rivales());

        for(int index = 0; index < X.length; index++)
        {
            if(sp.misJugadores()[X[index]].getY() < sp.rivales()[mCB].getY())
            {
                return X[index];
            }
        }

        return -1;
    }

    private int getSegundoMasCercano(Posicion p, int equipo)
    {
        int[] jd = null;

        if(equipo == X_EQUESTRIS)
            jd = getMisJugadoresMasCercanos(p);
        else
            jd = getRivalesMasCercanos(p);

        return jd[0];
    }

    private int[] getRivalesMasCercanos(Posicion p)
    {
        int mCB = sp.balon().indiceMasCercano(sp.rivales());
        int inx = 0;

        int[] j = new int[10];

        double[][] jd = new double[10][2];

        for(int nJ = 0; nJ < sp.misJugadores().length; nJ++)
        {
            if(nJ != mCB)
            {
                jd[inx][0] = nJ;
                jd[inx][1] = sp.misJugadores()[inx].distancia(p);
                inx++;
            }
        }//for

        jd = c.ordenaArrayDistancias(jd,2);

        for(int index = 0; index < 10; index++)
        {
            j[index] = (int)jd[index][0];
        }

        return j;
    }

    private int[] getMisJugadoresMasCercanos(Posicion p)
    {
        int mCB = sp.balon().indiceMasCercano(sp.misJugadores());
        int inx = 0;

        int[] j = new int[10];

        double[][] jd = new double[10][2];

        for(int nJ = 0; nJ < sp.misJugadores().length; nJ++)
        {
            if(nJ != mCB)
            {
                jd[inx][0] = nJ;
                jd[inx][1] = sp.misJugadores()[inx].distancia(p);
                inx++;
            }
        }//for

        jd = c.ordenaArrayDistancias(jd, 2);
        for(int index = 0; index < 10; index++)
        {
            j[index] = (int)jd[index][0];
        }

        return j;
    }

    private double getFuerzaIdeal(int jOrigen, int jDestino)
    {
        return sp.misJugadores()[jOrigen].distancia(sp.misJugadores()[jDestino]) / getRemateReal(jOrigen);
    }//getFuerzaIdeal


    private double getRemateReal(int nx)
    {
        return detalle.getJugadores()[nx].getRemate() * 1.2 + 1.2;
    }

    private int getPorteroRival(JugadorDetalle[] detalleRivales)
    {
        for(int index = 0; index < detalleRivales.length; index++)
        {
            if(detalleRivales[index].esPortero())
                return index;
        }

        return -1;
    }

    private void disparoAlArco(int nX, double d)//, boolean rAlto)
    {
        Posicion[] rivales = sp.rivales();

        int concurrencia = 0;

        for(Posicion p: rivales)
        {
            if(p.getX() >= Constantes.posteIzqArcoSup.getX() && p.getX() <= Constantes.posteDerArcoSup.getX()
               && p.getY() >= Constantes.LARGO_CAMPO_JUEGO/2 - Constantes.ANCHO_AREA_CHICA+1
               && p.getY() <= Constantes.LARGO_CAMPO_JUEGO/2)
            {
                concurrencia++;
            }
        }

        if(concurrencia >= 3 && d < DISTANCIA_FUERA && d > 18)
        {
            comandos.add(new ComandoGolpearBalon(nX, Constantes.centroArcoSup, 1, getAnguloVertical(nX, 30d)));
        }
        else
        {
            if(d < 18)
                comandos.add(new ComandoGolpearBalon(nX, Constantes.centroArcoSup, 1, getAnguloVertical(nX, 10d)));
            else
                regatea(nX);
        }
    }//disparoAlArco

    private double getAnguloVertical(int nx, double ang)
    {
        double theta = ang, theta_rad;
        double x, y, z, r, v;
        double dx, dy, dz, dr;

        //int it = 1;

        boolean suelo = false;
        boolean gol = true;

        while(theta < 65)
        {
            //theta = 0;//angulo vertical
            theta_rad = theta * Math.PI / 180d;//angulo vertica en radianes
            x = balon.getX();
            y = balon.getY();
            z = balon.getAltura();
            v = getRemateReal(nx);//detalle.getJugadores()[nx].getRemate() * 1;//velocidad
            r = 0;
            dx = Math.cos(balon.angulo(Constantes.centroArcoSup)) * v;
            dy = Math.sin(balon.angulo(Constantes.centroArcoSup)) * v;
            dz = c.round(v * Math.sin(theta_rad)* Math.cos(theta_rad), Constantes.G);
            dr = v * Math.cos(theta_rad);
            
            suelo = false;
            gol = true;

            while(y < 53d)// || dx < 0.09 || dy < 0.09)
            {
                if (!suelo && z == 0 && dz < Constantes.G * 3) {//condicion para que se arrastre
                    suelo = true;
                }
                if(suelo){
                    r = r + dr;
                    dr = dr * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                    dx = dx * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                    dy = dy * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                }else{
                    z = c.round(z + dz, Constantes.G);
                    r = r + dr;
                    dz = c.round(dz - Constantes.G, Constantes.G);
                    dr = dr * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                    dx = dx * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                    dy = dy * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                    if (z <= 0) {
                        dz = (-dz - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                        dz = c.round(dz, Constantes.G);
                    }
                }//else

                x = x + dx;
                y = y + dy;
                z = z + dz;
                
                Posicion p = new Posicion(x, y);
                int jc = p.indiceMasCercano(sp.rivales());
                if(p.distancia(sp.rivales()[jc]) <= Constantes.DISTANCIA_CONTROL_BALON_PORTERO)
                {
                    gol = false;
                    break;
                }
            }//while(y < 53)

            if(gol)
            {
                return theta;
            }

            theta += 5;
        }//while(theta < 65)

        return ang;
    }//getAnguloVertical

    private void paseX(int jX)
    {
        int jxd;

        double[] recta, circunferencia;

        double d = 0;
        double r = 2d; //radio del contrario

        boolean interseccion = true;
        //boolean existe = false;
        boolean pase = false;

        //List listJx = new ArrayList();
        //listJx.add(jX);

        List<Posicion> lpArea = new ArrayList<Posicion>();

        List<double[]> ofensivos = new ArrayList<double[]>();
        List<double[]> defensivos = new ArrayList<double[]>();

        double[][] dOfensivos = null;
        double[][] dDefensivos = null;

        for(int j = 1; j < sp.misJugadores().length; j++)
        {
            if(jX != j)
            {
                if(sp.misJugadores()[j].getY() >= sp.misJugadores()[jX].getY())
                {
                    double[] datos = {j, sp.misJugadores()[j].getX(), sp.misJugadores()[j].getY(), sp.misJugadores()[j].distancia(sp.misJugadores()[jX])};
                    ofensivos.add(datos);
                }
                else
                {
                    double[] datos = {j, sp.misJugadores()[j].getX(), sp.misJugadores()[j].getY(), sp.misJugadores()[j].distancia(sp.misJugadores()[jX])};
                    defensivos.add(datos);
                }
            }
        }//for misJugadores

        dOfensivos = (ofensivos.size() > 0) ? c.ordenaArrayDistancias(c.toArray(ofensivos), 4) : new double[0][0];
        dDefensivos = (defensivos.size() > 0) ? c.ordenaArrayDistancias(c.toArray(defensivos), 4) : new double[0][0];

        for(int nx = 0; nx < dOfensivos.length; nx++)
        {
            //listJx.add(jxd);
            jxd = (int)dOfensivos[nx][0];

            recta = c.getRecta(sp.misJugadores()[jX].getX(), sp.misJugadores()[jX].getY(), sp.misJugadores()[jxd].getX(), sp.misJugadores()[jxd].getY());

            for(int j = 0; j < sp.rivales().length; j++)
            {
                lpArea = getAreaPase(jX, jxd);
                if(sp.rivales()[j].getX() > lpArea.get(0).getX() && sp.rivales()[j].getX() < lpArea.get(1).getX()
                   && sp.rivales()[j].getY() > lpArea.get(0).getY() && sp.rivales()[j].getY() < lpArea.get(1).getY())
                {
                    circunferencia = c.getCircunferencia(sp.rivales()[j].getX(), sp.rivales()[j].getY(), r);

                    interseccion = c.intersectaRectaCircunferencia(recta, circunferencia);

                    d = dOfensivos[nx][3];

                    if(interseccion)
                    {
                        pase = false;
                        break;
                    }

                    pase = true;
                }
            }//for rivales

            if(pase)
            {
                if(d < 13)
                    comandos.add(new ComandoGolpearBalon(jX, sp.misJugadores()[jxd], getFuerzaIdeal(jX, jxd), false));
                else
                    comandos.add(new ComandoGolpearBalon(jX, sp.misJugadores()[jxd], getFuerzaIdeal(jX, jxd), 15));
                break;//Sale del for de dOfensivos
            }
        }//for dOfensivos
        
        if(!pase && ofensivos.size() > 1)
        {
            for(int nx = 0; nx < dDefensivos.length; nx++)
            {
                //listJx.add(jxd);
                jxd = (int)dDefensivos[nx][0];

                recta = c.getRecta(sp.misJugadores()[jX].getX(), sp.misJugadores()[jX].getY(), sp.misJugadores()[jxd].getX(), sp.misJugadores()[jxd].getY());

                for(int j = 0; j < sp.rivales().length; j++)
                {
                    lpArea = getAreaPase(jX, jxd);
                    if(sp.rivales()[j].getX() > lpArea.get(0).getX() && sp.rivales()[j].getX() < lpArea.get(1).getX()
                       && sp.rivales()[j].getY() > lpArea.get(0).getY() && sp.rivales()[j].getY() < lpArea.get(1).getY())
                    {
                        circunferencia = c.getCircunferencia(sp.rivales()[j].getX(), sp.rivales()[j].getY(), 3d);

                        interseccion = c.intersectaRectaCircunferencia(recta, circunferencia);

                        if(interseccion)
                        {
                            pase = false;
                            break;
                        }

                        pase = true;
                    }
                }//for rivales

                if(pase)
                {
                    if(d < 13)
                        comandos.add(new ComandoGolpearBalon(jX, sp.misJugadores()[jxd], getFuerzaIdeal(jX, jxd), false));
                    else
                        comandos.add(new ComandoGolpearBalon(jX, sp.misJugadores()[jxd], getFuerzaIdeal(jX, jxd), 15));
                    break;//Sale del for de dOfensivos
                }
            }//for dDefensivos
        }//if !pase

        if(!pase && jX > -1)
            comandos.add(new ComandoGolpearBalon(jX, Constantes.centroArcoSup, 1, true));
    }//paseX

    private List<Posicion> getAreaPase(int jxo, int jxd)
    {
        double x1, y1, x2, y2;

        if(sp.misJugadores()[jxo].getX() < sp.misJugadores()[jxd].getX())
        {
            x1 = sp.misJugadores()[jxo].getX();
            x2 = sp.misJugadores()[jxd].getX();
        }
        else
        {
            x1 = sp.misJugadores()[jxd].getX();
            x2 = sp.misJugadores()[jxo].getX();
        }

        if(sp.misJugadores()[jxo].getY() < sp.misJugadores()[jxd].getY())
        {
            y1 = sp.misJugadores()[jxo].getY();
            y2 = sp.misJugadores()[jxd].getY();
        }
        else
        {
            y1 = sp.misJugadores()[jxd].getY();
            y2 = sp.misJugadores()[jxo].getY();
        }

        List<Posicion> list = new ArrayList<Posicion>();
        list.add(new Posicion(x1, y1));
        list.add(new Posicion(x2, y2));

        return list;
    }

    private boolean puedeRematar(int nx)
    {
        int[] x = sp.puedenRematar();

        for(int j = 0; j < x.length; j++)
        {
            if(x[j] == nx)
                return true;
        }

        return false;
    }

    private void mueveMedioIzquierdo()
    {
        double x = sp.misJugadores()[6].getX();
        double y = sp.misJugadores()[6].getY();

        if(pB == X_EQUESTRIS)
        {
            if(sp.balon().getY() < Constantes.LARGO_CAMPO_JUEGO/2 - 18)
            {
                if(Constantes.ANCHO_CAMPO_JUEGO/2/3 > sp.balon().getX() && sp.balon().getX() > 0)
                {
                    x = -Constantes.ANCHO_CAMPO_JUEGO/2 + sp.balon().getX();
                }
                else
                    if(Constantes.ANCHO_CAMPO_JUEGO/2/3 < sp.balon().getX() && Constantes.ANCHO_CAMPO_JUEGO/2/3*2 > sp.balon().getX())
                    {
                        x = -Constantes.ANCHO_CAMPO_JUEGO/2/3*2 + sp.balon().getX();
                    }
                    else
                        if(Constantes.ANCHO_CAMPO_JUEGO/2 > sp.balon().getX() && Constantes.ANCHO_CAMPO_JUEGO/2/3*2 < sp.balon().getX())
                        {
                            x = -Constantes.ANCHO_CAMPO_JUEGO/2/3 + sp.balon().getX();
                        }

                y = sp.balon().getY() + 5;
                y = Math.min(y, 51);
            }// y del balon < 18
            else
            {
                //El balon esta ya cerca del area, el medio izquierdo debe ir a rematar (aplicamos mirror)
                x = -sp.balon().getX();
                y = sp.balon().getY() + 5;
                y = Math.min(y, 51);
            }

            comandos.add(new ComandoIrA(6, new Posicion(x, y)));
        }//if pB X_EQUESTRIS
    }

    private void mueveMedioDerecho()
    {
        double x = sp.misJugadores()[5].getX();
        double y = sp.misJugadores()[5].getY();

        if(pB == X_EQUESTRIS)
        {
            if(sp.balon().getY() < Constantes.LARGO_CAMPO_JUEGO/2 - 18)
            {
                if(-Constantes.ANCHO_CAMPO_JUEGO/2/3 > sp.balon().getX() && sp.balon().getX() > 0)
                {
                    x = Constantes.ANCHO_CAMPO_JUEGO/2 + sp.balon().getX();
                }
                else
                    if(-Constantes.ANCHO_CAMPO_JUEGO/2/3 < sp.balon().getX() && -Constantes.ANCHO_CAMPO_JUEGO/2/3*2 > sp.balon().getX())
                    {
                        x = Constantes.ANCHO_CAMPO_JUEGO/2/3*2 + sp.balon().getX();
                    }
                    else
                        if(-Constantes.ANCHO_CAMPO_JUEGO/2 > sp.balon().getX() && -Constantes.ANCHO_CAMPO_JUEGO/2/3*2 < sp.balon().getX())
                        {
                            x = Constantes.ANCHO_CAMPO_JUEGO/2/3 + sp.balon().getX();
                        }

                y = sp.balon().getY() + 5;
                y = Math.min(y, 51);
            }// y del balon < 18
            else
            {
                //El balon esta ya cerca del area, el medio izquierdo debe ir a rematar (aplicamos mirror)
                x = -sp.balon().getX();
                y = sp.balon().getY() + 5;
                y = Math.min(y, 51);
            }

            comandos.add(new ComandoIrA(5, new Posicion(x, y)));
        }//if pB X_EQUESTRIS
    }

    private void mueveDelanteroIzquierdo()
    {
        double x = alineacion1[8].getX();
        double y = sp.misJugadores()[8].getY();

        if(pB == X_EQUESTRIS)
        {
            if(sp.balon().getY() < -Constantes.LARGO_CAMPO_JUEGO/2/4)
            {
                y = Constantes.RADIO_CIRCULO_CENTRAL;
            }
            else
            {
                y = sp.balon().getY() + 20;
                if(y > Constantes.LARGO_CAMPO_JUEGO/2 - Constantes.ANCHO_AREA_CHICA-2)
                {
                    x = -1d;
                    y = Constantes.LARGO_CAMPO_JUEGO/2 - Constantes.ANCHO_AREA_CHICA - 2;
                }
            }

            comandos.add(new ComandoIrA(8, new Posicion(x, y)));
        }//if pB X_EQUESTRIS
    }

    private void mueveDelanteroDerecho()
    {
        double x = alineacion1[10].getX();
        double y = sp.misJugadores()[10].getY();

        if(pB == X_EQUESTRIS)
        {
            if(sp.balon().getY() < -Constantes.LARGO_CAMPO_JUEGO/2/4)
            {
                y = Constantes.RADIO_CIRCULO_CENTRAL;
            }
            else
            {
                if(y > Constantes.LARGO_CAMPO_JUEGO/2 - Constantes.ANCHO_AREA_CHICA-2)
                {
                    x = 1d;
                    y = Constantes.LARGO_CAMPO_JUEGO/2 - Constantes.ANCHO_AREA_CHICA - 2;
                }
                else
                {
                    y = sp.balon().getY() + 20;
                }
            }

            comandos.add(new ComandoIrA(10, new Posicion(x, y)));
        }//if pB X_EQUESTRIS
    }

    private void mueveDefensas()
    {
        double x, y;

        for(int nx = 1; nx < 5; nx++)
        {
            x = sp.misJugadores()[nx].getX();
            y = sp.misJugadores()[nx].getY();
            switch(nx)
            {
                case 4:
                case 1:
                    if(sp.balon().getY() < -Constantes.LARGO_CAMPO_JUEGO/2/4 && sp.balon().getX() > 0)
                    {
                        if(jcp[0] != nx && jcp[1] != nx)
                        {
                            x = Constantes.posteIzqArcoInf.getX() + (Math.random()*7);
                            y = -52.2 + 4;
                        }
                    }
                    else
                    {
                        x = alineacion1[nx].getX();
                        y = alineacion1[nx].getY();
                    }
                    break;

               case 2:
               case 3:
                    if(sp.balon().getY() < -Constantes.LARGO_CAMPO_JUEGO/2/4 && sp.balon().getX() < 0)
                    {
                        if(jcp[0] != nx && jcp[1] != nx)
                        {
                            x = Constantes.posteDerArcoInf.getX() - (Math.random()*7);
                            y = -52.2 + 4;
                        }
                    }
                    else
                    {
                        x = alineacion1[nx].getX();
                        y = alineacion1[nx].getY();
                    }
                    break;
            }

            comandos.add(new ComandoIrA(nx, new Posicion(x, y)));
        }//for
    }

    private void mueveMedioOfensivo()
    {
        //double x = sp.misJugadores()[9].getX();
        double x = alineacion1[9].getX();
        double y = sp.misJugadores()[9].getY();

        if(pB == X_EQUESTRIS)
        {
            if(sp.balon().getY() < Constantes.LARGO_CAMPO_JUEGO/2-Constantes.ANCHO_AREA_GRANDE+1)
            {
                y = sp.balon().getY() + 10;
                y = Math.max(y, alineacion1[9].getY());
            }
            else
            {
                y = 32;
            }
        }
        else
        {
            x = alineacion1[9].getX();
            y = alineacion1[9].getY();
        }

        comandos.add(new ComandoIrA(9, new Posicion(x, y)));
    }
}